package hk.com.fgoproduction.getdroplets.Lib.DB

import android.content.Context
import com.alibaba.fastjson.JSON
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStream
import java.io.InputStreamReader

class FileRevDb(val ctx: Context) {

    companion object {
        private var instance: FileRevDb? = null
        private val lock = Any()

        fun FileRevDbFactory (ctx: Context) : FileRevDb {
            if (instance == null){
                synchronized(lock) {
                    if (instance == null) {
                        instance = FileRevDb(ctx)
                    }
                }
            }

            return instance as FileRevDb
        }

        fun clearInstance() {
            synchronized(lock) {
                instance = null
            }
        }
    }

    var db = ""
        private set

    fun create(dbName: String) {
        if (ctx.getFileStreamPath(dbName).exists())
            return
        else {
            val out = ctx.openFileOutput(dbName, Context.MODE_PRIVATE)
            out.close()
        }
    }

    fun init(dbName: String) : Boolean {
        if (ctx.getFileStreamPath(dbName).exists()) {
            db = dbName
            return true
        } else {
            return false
        }
    }

    fun put(list: FileRevBeanGp) {
        if (emptyDbName()) throw EmptyDbOptionException()

        var json = isToString(ctx.openFileInput(db))
        val obj = JSON.parseObject(json, FileRevBeanGp::class.java)
        if (obj != null) {
            list.list.forEach {
                val srcPath = it.fullPath
                val objBean = obj.list.find { it.fullPath == srcPath }
                if (objBean == null)
                    obj.list.add(it)
                else
                    obj.list[obj.list.indexOf(objBean)] = it
            }
            json = JSON.toJSONString(obj)
        } else {
            json += JSON.toJSONString(list)
        }
        stringToOs(json)
    }

    fun put(bean: FileRevBean) {
        if (emptyDbName()) throw EmptyDbOptionException()

        var json = isToString(ctx.openFileInput(db))
        val obj = JSON.parseObject(json, FileRevBeanGp::class.java)
        if (obj != null) {
            val objBean = obj.list.find { it.fullPath == bean.fullPath }
            if (objBean == null)
                obj.list.add(bean)
            else {
                obj.list[obj.list.indexOf(objBean)] = bean
            }
            json += JSON.toJSONString(obj)
        } else {
            val list = FileRevBeanGp()
            list.list.add(bean)
            json += JSON.toJSONString(list)
        }
        stringToOs(json)
    }

    fun get(fullPath: String) : FileRevBean? {
        if (emptyDbName()) throw EmptyDbOptionException()

        val raw = isToString(ctx.openFileInput(db))
        val obj = JSON.parseObject(raw, FileRevBeanGp::class.java)
        val result = obj.list.find { it.fullPath == fullPath } ?: return null
        return result
    }

    fun close() {
        db = ""
    }

    private fun isToString(`is`: InputStream) : String {
        var buffer: BufferedReader? = null
        var builder = StringBuilder()
        var line = ""

        try {
            buffer = BufferedReader(InputStreamReader(`is`))
            while (true) {
                line = buffer.readLine() ?: break
                builder.append(line)
            }
        } catch (e: IOException) {
            throw e
        } finally {
            if (buffer != null) {
                try {
                    buffer.close()
                } catch (e: IOException) {
                    throw e
                }
            }
        }

        return builder.toString()
    }

    private fun stringToOs(text: String) {
        val out = ctx.openFileOutput(db, Context.MODE_PRIVATE)
        out.write(text.toByteArray())
        out.close()
    }

    private fun emptyDbName() : Boolean{
        return db == ""
    }

    class EmptyDbOptionException : Exception("Empty DB Option!")
}